package org.jet.emall.prod.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.jet.emall.common.constant.CategoryIsFloorValue;
import org.jet.emall.common.constant.CategoryShowValue;
import org.jet.emall.prod.dto.CategoryDTO;
import org.jet.emall.prod.dto.ProdAttrDTO;
import org.jet.emall.prod.dto.ProdSpecDTO;
import org.jet.emall.prod.po.*;
import org.jet.emall.prod.service.mp.*;
import org.jet.emall.prod.transfer.CategoryDtoTransfer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author xiaozai
 * @version 1.0
 * @date 2020-04-15 17:28
 */
@Service
public class CustomProductCategoryServiceImpl implements CustomProductCategoryService {

    @Autowired
    private IProdCateService prodCateService;

    @Autowired
    private IProdCateBrandService prodCateBrandService;

    @Autowired
    private IProdAttrService prodAttrService;

    @Autowired
    private IProdSpecService prodSpecService;

    @Autowired
    private IProdSpecOptionService prodSpecOptionService;

    @Autowired
    private IProdAttrOptionService prodAttrOptionService;

    @Autowired
    private IProdSkuSpecOptionService prodSkuSpecOptionService;

    @Autowired
    private IProdSkuAttrOptionService prodSkuAttrOptionService;

    @Autowired
    private IProdSpuService prodSpuService;

    @Override
    public List<CategoryDTO> getProductCategories() {
        List<ProdCate> list = prodCateService.list();
        List<CategoryDTO> dtoList = CategoryDtoTransfer.INSTANCE.toDtoList(list);
        List<CategoryDTO> result = makeTree(dtoList);
        return result;
    }

    @Override
    public List<CategoryDTO> getProductCategoriesOnlyShow() {
        Wrapper<ProdCate> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdCate>) wrapper).eq("is_show", CategoryShowValue.SHOW);
        List<ProdCate> list = prodCateService.list(wrapper);
        List<CategoryDTO> dtoList = CategoryDtoTransfer.INSTANCE.toDtoList(list);
        return makeTree(dtoList);
    }

    @Override
    public List<ProdAttrDTO> findAttrsOfCate3(Integer cate3Id) {
        Wrapper<ProdAttr> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdAttr>) wrapper).eq("cate_id",cate3Id);
        List<ProdAttr> list = prodAttrService.list(wrapper);
        List<ProdAttrDTO> dtoList = CategoryDtoTransfer.INSTANCE.toAttrDtoList(list);
        return dtoList;
    }

    @Override
    public List<ProdSpecDTO> findSpecsOfCate3(Integer cate3Id) {
        Wrapper<ProdSpec> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdSpec>) wrapper).eq("cate_id",cate3Id);
        List<ProdSpec> list = prodSpecService.list(wrapper);
        List<ProdSpecDTO> dtoList = CategoryDtoTransfer.INSTANCE.toSpecDtoList(list);
        return dtoList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteSpec(Integer specId) {

        Wrapper<ProdSpecOption> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdSpecOption>) wrapper).eq("spec_id",specId);
        List<ProdSpecOption> list = prodSpecOptionService.list(wrapper);
        List<Integer> idList = list.stream().mapToInt(v -> v.getId()).collect(ArrayList<Integer>::new, List::add, List::addAll);
        if(idList!=null && !idList.isEmpty()){
            Wrapper<ProdSkuSpecOption> wrapper2 = new QueryWrapper<>();
            ((QueryWrapper<ProdSkuSpecOption>) wrapper2).in("spec_option_id",idList);
            prodSkuSpecOptionService.remove(wrapper2);
        }

        prodSpecOptionService.removeByIds(idList);

        prodSpecService.removeById(specId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteAttr(Integer attrId) {
        Wrapper<ProdAttrOption> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdAttrOption>) wrapper).eq("attr_id",attrId);
        List<ProdAttrOption> list = prodAttrOptionService.list(wrapper);
        ArrayList<Integer> idList = list.stream().mapToInt(v -> v.getId()).collect(ArrayList<Integer>::new, List::add, List::addAll);
        if(idList!=null && !idList.isEmpty()){
            Wrapper<ProdSkuAttrOption> wrapper2 = new QueryWrapper<>();
            ((QueryWrapper<ProdSkuAttrOption>) wrapper2).in("attr_option_id",idList);
            prodSkuAttrOptionService.remove(wrapper2);
        }

        prodAttrOptionService.removeByIds(idList);
        prodAttrService.removeById(attrId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addAttrForCate3(Integer cate3Id, String attrName) {

        Wrapper<ProdAttr> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdAttr>) wrapper).eq("cate_id",cate3Id)
                .eq("name",attrName);
        ProdAttr prodAttr = prodAttrService.getOne(wrapper);
        if(prodAttr!=null){
            throw new RuntimeException("该属性已存在");
        }
        prodAttrService.save( new ProdAttr().setCateId(cate3Id).setName(attrName) );

//        TbProdAttrExample ex = new TbProdAttrExample();
//        ex.createCriteria().andCateIdEqualTo(cate3Id).andNameEqualTo(attrName);
//
//        List<TbProdAttr> tbProdAttrs = prodAttrMapper.selectByExample(ex);
//        if (tbProdAttrs != null && !tbProdAttrs.isEmpty()) {
//            throw new RuntimeException("该属性已存在");
//        }
//        TbProdAttr tbProdAttr = new TbProdAttr();
//        tbProdAttr.setName(attrName);
//        tbProdAttr.setCateId(cate3Id);
//        prodAttrMapper.insertSelective(tbProdAttr);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addSpecForCate3(Integer cate3Id, String specName) {
        Wrapper<ProdSpec> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdSpec>) wrapper).eq("cate_id",cate3Id)
                .eq("name",specName);
        ProdSpec prodSpec = prodSpecService.getOne(wrapper);
        if(prodSpec!=null){
            throw new RuntimeException("该规格已存在");
        }
        prodSpecService.save(new ProdSpec().setCateId(cate3Id).setName(specName));
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAttr(Integer attrId, String name) {
        prodAttrService.updateById(new ProdAttr().setId(attrId).setName(name));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateSpec(Integer specId, String name) {
        prodSpecService.updateById(new ProdSpec().setId(specId).setName(name));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateCateName(Integer cateId, String name) {
        prodCateService.updateById(new ProdCate().setId(cateId).setName(name));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateCateShow(Integer cateId, Byte show) {
        prodCateService.updateById(new ProdCate().setId(cateId).setIsShow(show));
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateCateRemarks(Integer cateId, String remarks) {
        prodCateService.updateById(new ProdCate().setId(cateId).setRemarks(remarks));
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveCate(CategoryDTO cateDTO) {
        ProdCate prodCate = CategoryDtoTransfer.INSTANCE.toPo(cateDTO);
        prodCateService.save(prodCate);

        if(prodCate.getPid()>0){
            ProdCate parent = new ProdCate();
            parent.setId(prodCate.getPid()).setIsFloor(CategoryIsFloorValue.FLOOR);
            prodCateService.updateById(parent);
        }
    }

    @Override
    public void deleteCate(Integer cateId) {
        ProdCate cate = prodCateService.getById(cateId);
        if(!canBeDeleted(cate)){
            throw new RuntimeException("该分类还有商品，不能删除");
        }
        rdeleteChildren(cateId);
    }


    /**
     *  递归删除分类节点
     * @param pid
     */
    private void rdeleteChildren(Integer pid){
        QueryWrapper<ProdCate> wrapper = new QueryWrapper<ProdCate>().eq("pid", pid);
        List<ProdCate> prodCates = prodCateService.list(wrapper);
        //有子节点先删子节点
        if(prodCates!=null && !prodCates.isEmpty()){
            prodCates.forEach(prodCate -> {
                rdeleteChildren(prodCate.getId());
            });
        }
        //删自己
        prodCateService.removeById(pid);


    }


    private boolean canBeDeleted(ProdCate cate){

        if( cate.getIsFloor().equals(CategoryIsFloorValue.FLOOR)){
            Wrapper<ProdCate> wrapper = new QueryWrapper<>();
            ((QueryWrapper<ProdCate>) wrapper).eq("pid",cate.getId());
            List<ProdCate> list = prodCateService.list(wrapper);
            if(list!=null && !list.isEmpty()){
               for(int i=0;i<list.size();i++){
                   if(!canBeDeleted(list.get(i))){
                       return false;
                   }
               }
            }
        }else{
            Wrapper<ProdSpu> wrapper = new QueryWrapper<>();
            ((QueryWrapper<ProdSpu>) wrapper).eq("cate_id",cate.getId());
            List<ProdSpu> list = prodSpuService.list(wrapper);
            if(list!=null&& !list.isEmpty()){
                return false;
            }
        }
        return true;
    }

    private List<CategoryDTO> makeTree(List<CategoryDTO> dtoList){
        Map<Integer,CategoryDTO> map = new HashMap<>(64);
        dtoList.forEach(dto->{
            map.put(dto.getId(),dto);
        });
        map.forEach((key,value)->{
            if(value.getPid()!=0) {
                CategoryDTO p = map.get(value.getPid());
                List<CategoryDTO> children = p.getChildren();
                if(children==null){
                    children = new LinkedList<>();
                    p.setChildren(children);
                }
                children.add(value);
            }
        });
        dtoList.removeIf(v-> v.getPid()!=0);
        map.clear();
        return dtoList;
    }
}
